home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
Clipper.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-21
|
12KB
|
617 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "Clipper.h"
#include "Class.h"
#include "Math.h"
#include "View.h"
#include "Error.h"
#include "Token.h"
#include "Window.h"
#include "String.h"
#include "WindowPort.h"
#include "Collection.h"
//---- Clipper -----------------------------------------------------------------
NewMetaImpl(Clipper,VObject, (TP(vop), TB(deleteVop), T(minExtent),
T(relOrigin), T(scale), TP(bgcolor)));
Clipper::Clipper(VObject *vp, Point minsize, int id, Ink *bg)
: VObject(minsize, id)
{
if (bg == 0)
bg= gInkWhite;
bgcolor= bg;
vop= 0;
relOrigin= gPoint0;
scale= 1.0;
SetMinExtent(minsize);
ResetFlag(eVObjOpen);
deleteVop= FALSE;
Add(vp);
}
Clipper::~Clipper()
{
if (vop) {
VObject *tmp= vop;
vop= 0;
tmp->ClearContainer(this);
if (deleteVop)
delete tmp;
}
}
void Clipper::Open(bool mode)
{
if (IsOpen() != mode) {
VObject::Open(mode);
if (vop)
vop->Open(mode);
}
}
void Clipper::Add(VObject *vp)
{
Remove(vop);
vop= vp;
if (vop) {
vop->SetContainer(this);
if (IsOpen() && !vop->IsOpen())
vop->Open(TRUE);
ViewSizeChanged();
}
}
VObject *Clipper::Remove(VObject *vp)
{
if (vop && vop == vp) {
vop= 0;
if (vp->IsOpen())
vp->Open(FALSE);
vp->ClearContainer(this);
return vp;
}
return 0;
}
void Clipper::SetContainer(VObject *v)
{
VObject::SetContainer(v);
if (vop && !vop->IsKindOf(View)) {
vop->CalcExtent();
vop->SetOrigin(gPoint0);
}
}
void Clipper::Enable(bool b, bool redraw)
{
VObject::Enable(b, redraw);
if (vop)
vop->Enable(b, redraw);
}
void Clipper::ScaleUp(Point &p)
{
p.x= (int) ((float)p.x * scale + 0.5);
p.y= (int) ((float)p.y * scale + 0.5);
}
void Clipper::ScaleDown(Point &p)
{
p.x= (int) ((float)p.x / scale + 0.5);
p.y= (int) ((float)p.y / scale + 0.5);
}
Point Clipper::GetViewSize()
{
Point p;
if (vop)
p= vop->GetExtent();
ScaleUp(p);
return p;
}
Rectangle Clipper::GetViewedRect()
{
return Rectangle(relOrigin, contentRect.extent);
}
void Clipper::SetZoom(float zoom)
{
scale= zoom;
ViewSizeChanged();
ForceRedraw();
}
Metric Clipper::GetMinSize()
{
Point me(minExtent);
if (vop && (minExtent.x == -1 || minExtent.y == -1)) {
Point e= vop->GetMinSize().extent;
if (minExtent.x == -1)
me.x= e.x;
if (minExtent.y == -1)
me.y= e.y;
}
//if (vop)
// return Metric(me, vop->Base());
return me;
}
void Clipper::SetMinExtent(Point e)
{
minExtent= e;
if (e.x == -1)
SetFlag(eVObjHFixed);
if (e.y == -1)
SetFlag(eVObjVFixed);
}
void Clipper::ViewSizeChanged()
{
if (vop) {
Point newsize(vop->GetExtent());
ScaleUp(newsize);
Send(GetId(), cPartViewSize, &newsize);
Normalize();
}
}
void Clipper::InvalidateViewRect(Rectangle r)
{
r.origin= ContainerPoint(r.origin);
ScaleUp(r.extent);
InvalidateRect(r);
}
void Clipper::SetExtent(Point e)
{
VObject::SetExtent(e);
Normalize();
}
void Clipper::SetOrigin(Point at)
{
VObject::SetOrigin(at);
if (vop)
vop->SetOrigin(gPoint0);
}
void Clipper::Normalize()
{
Point vs(GetViewSize()), ee(GetExtent()), scroll;
if (vs.x < ee.x)
scroll.x= -relOrigin.x;
else if (vs.x < relOrigin.x+ee.x)
scroll.x= relOrigin.x+ee.x - vs.x;
if (vs.y < ee.y)
scroll.y= -relOrigin.y;
else if (vs.y < relOrigin.y+ee.y)
scroll.y= relOrigin.y+ee.y - vs.y;
Scroll(cPartScrollRel, scroll);
}
void Clipper::Focus()
{
if (GetContainer()) {
GetContainer()->Focus();
GrClipFurther(contentRect);
GrTranslate(Offset());
GrScale(scale, scale);
}
}
void Clipper::DrawInner(Rectangle r, bool)
{
if (bgcolor && bgcolor != ePatNone && !gPrinting)
GrPaintRect(r, bgcolor);
if (vop) {
GrState gs;
GrClipFurther(r);
GrTranslate(Offset());
GrScale(scale, scale);
r.origin-= Offset();
ScaleDown(r.origin);
ScaleDown(r.extent);
vop->DrawAll(r, FALSE);
}
}
VObject *Clipper::Detect(BoolFun find, void *arg)
{
VObject *v;
if (vop && (v= vop->Detect(find, arg)))
return v;
return VObject::Detect(find, arg);
}
void Clipper::ReadEvent(Token &t, int timeout, bool overread)
{
VObject::ReadEvent(t, timeout, overread);
t.Pos-= Offset();
ScaleDown(t.Pos);
}
Command *Clipper::DispatchEvents(Point lp, Token &t, Clipper *vf)
{
Command *cmd= 0;
lp-= Offset();
ScaleDown(lp);
if (vop)
cmd= vop->Input(lp, t, this);
else
cmd= VObject::DispatchEvents(lp, t, vf);
if (cmd)
PerformCommand(cmd);
return gNoChanges;
}
Point Clipper::ContainerPoint(Point p)
{
ScaleUp(p);
return p+Offset();
}
void Clipper::SetBgInk(Ink *ip)
{
bgcolor= ip;
ForceRedraw();
}
Ink *Clipper::GetBgInk()
{
return bgcolor;
}
//---- Scrolling ----------------------------------------------------------------
Point Clipper::AutoScroll(Point p)
{
ScaleUp(p);
p-= relOrigin;
Point scroll= Rectangle(contentRect.extent).Constrain(p);
Scroll(cPartScrollRel, scroll-p);
return scroll;
}
void Clipper::RevealRect(Rectangle r, Point minToSee)
{
ScaleUp(r.extent);
ScaleUp(minToSee);
VObject::RevealRect(Rectangle(ContainerPoint(r.origin), r.extent), minToSee);
ScaleUp(r.origin);
Rectangle vr(relOrigin, contentRect.extent);
Rectangle ir(Inter(r, vr));
if (ir.IsEmpty() || ir.extent.x < minToSee.x || ir.extent.y < minToSee.y)
Scroll(cPartScrollRel, r.AmountToTranslateWithin(vr));
}
void Clipper::RevealAlign(Rectangle r, VObjAlign al)
{
ScaleUp(r.origin);
ScaleUp(r.extent);
Rectangle vr= GetViewedRect();
Point scroll;
switch (al & eVObjH) {
case eVObjHCenter:
scroll.x= (vr.Center().x - r.Center().x)/2;
break;
case eVObjHRight:
scroll.x= vr.NE().x - r.NE().x;
break;
default:
scroll.x= vr.NW().x - r.NW().x;
break;
}
switch (al & eVObjV) {
case eVObjVCenter:
scroll.y= (vr.Center().y - r.Center().y)/2;
break;
case eVObjVBottom:
scroll.y= vr.SW().y - r.SW().y;
break;
default:
scroll.y= vr.NW().y - r.NW().y;
break;
}
Scroll(cPartScrollRel, scroll);
}
void Clipper::ExtentChanged(VObject*)
{
ViewSizeChanged();
}
void Clipper::Control(int id, int part, void *val)
{
if (part == cPartExtentChanged) {
if (val == vop)
ViewSizeChanged();
}
VObject::Control(id, part, val);
}
void Clipper::SendDown(int id, int part, void *val)
{
if (vop)
vop->SendDown(id, part, val);
}
void Clipper::Scroll(int mode, Point scroll, bool redraw)
{
Point leftCorner, newOrigin, delta;
if (GetContainer() == 0)
return;
switch(mode) {
case cPartScrollStep:
delta= 32 * -scroll;
break;
case cPartScrollPage:
delta= (contentRect.extent-32) * -scroll;
break;
case cPartScrollAbs:
delta= relOrigin - scroll;
break;
case cPartScrollHAbs:
delta.x= relOrigin.x - scroll.x;
break;
case cPartScrollVAbs:
delta.y= relOrigin.y - scroll.y;
break;
case cPartScrollRel:
delta= scroll;
break;
}
if (delta == gPoint0)
return;
leftCorner= Max(gPoint0, GetViewSize() - contentRect.extent);
newOrigin= relOrigin-delta;
if (vop && vop->IsKindOf(View))
((View*)vop)->ConstrainScroll(&newOrigin);
delta= relOrigin - Min(Max(gPoint0, newOrigin), leftCorner);
if (delta == gPoint0)
return;
if (! IsOpen())
redraw= FALSE;
if (redraw) {
UpdateEvent();
Focus();
relOrigin-= delta;
((WindowPort*)GrGetPort())->Scroll(delta);
} else
relOrigin-= delta;
Send(GetId(), cPartScrollPos, &relOrigin);
UpdateEvent();
}
// returns TRUE on exit loop
bool Clipper::TrackOnce(Command** tracker, TrackPhase atp, Point ap, Point pp, Point lp)
{
Command *newTracker;
if (*tracker == 0) {
*tracker= gNoChanges;
return TRUE;
}
newTracker= (*tracker)->TrackMouse(atp, ap, pp, lp);
if (newTracker != *tracker) {
if (*tracker && *tracker != gNoChanges)
delete *tracker;
*tracker= newTracker;
return (newTracker == gNoChanges);
}
return FALSE;
}
// called from View
void Clipper::DrawInFocus(VoidObjMemberFunc of, Object *op, void *v1, void *v2, void *v3, void *v4)
{
if (IsOpen()) {
Focus();
(op->*of)(v1, v2, v3, v4);
}
}
void Clipper::Feedback(Object *tracker, void *ap, void *pp, void *turniton)
{
GrPattern pat= ePatBlack;
if (((Command*)tracker)->TestFlag(eCmdFullScreen) ||
! ((Command*)tracker)->TestFlag(eCmdNoReplFeedback))
pat= ePatXor;
GrSetInk(pat);
GrSetPenInk(pat);
GrSetTextInk(pat);
GrSetPenSize(1);
((Command*)tracker)->TrackFeedback(*((Point*)ap), *((Point*)pp), *((bool*)turniton));
UpdateEvent();
}
void Clipper::FeedbackOnce(Command *tracker, Point ap, Point pp, bool turniton)
{
if (!tracker->TestFlag(eCmdNoReplFeedback) && vop && vop->IsKindOf(View))
((View*)vop)->ShowInAllClippers((VoidObjMemberFunc)&Clipper::Feedback, this,
(void*) tracker, (void*) &ap, (void*) &pp, (void*) &turniton);
else
Feedback(tracker, (void*) &ap, (void*) &pp, (void*) &turniton);
}
Command *Clipper::TrackInContent(Point lp, Token token, Command* tracker)
{
static int level= 0;
static bool haveSeenUp;
bool autoscroll= FALSE, havereset, isidle= FALSE, fullscreen, done;
Point newlp, ap, pp, oldrelorigin;
Window *bwin= GetWindow();
level++;
if (level == 1)
haveSeenUp= FALSE;
Focus();
bwin->Grab(TRUE, fullscreen= tracker->TestFlag(eCmdFullScreen));
havereset= FALSE;
restart2:
ap= pp= lp;
tracker->TrackConstrain(ap, pp, &lp);
ap= pp= lp;
if (TrackOnce(&tracker, eTrackPress, ap, pp, lp))
goto out;
FeedbackOnce(tracker, ap, pp, TRUE);
restart:
while (IsOpen()) {
if (level > 0 && haveSeenUp && !tracker->TestFlag(eCmdMoveEvents))
break;
done= FALSE;
while (!done) {
if (isidle || autoscroll)
ReadEvent(token, 0, TRUE);
else
ReadEvent(token, 100, FALSE);
switch (token.Code) {
case eEvtNone:
if (autoscroll) {
token.Code= eEvtLocMove; // simulate a move event
done= TRUE;
break;
}
if (tracker->TestFlag(eCmdIdleEvents)) {
done= isidle= TRUE;
break;
}
//done= haveSeenUp= TRUE;
break;
case eEvtRightButton:
case eEvtMiddleButton:
case eEvtLeftButton:
if (token.Flags & eFlgButDown)
haveSeenUp= TRUE;
else
goto restart2;
done= TRUE; // return button event immediately
break;
case eEvtLocMove:
done= TRUE;
break;
case eEvtIdle: // ignore idle events
break;
default:
break;
}
}
lp= token.Pos;
if (haveSeenUp)
break;
FeedbackOnce(tracker, ap, pp, FALSE); // clear previous feedback
tracker->TrackConstrain(ap, pp, &lp);
if (! fullscreen) {
oldrelorigin= relOrigin;
newlp= AutoScroll(lp);
if (relOrigin != oldrelorigin) {
autoscroll= TRUE;
lp= newlp + relOrigin;
} else
autoscroll= FALSE;
}
oldrelorigin= relOrigin;
if (TrackOnce(&tracker,
token.Code == eEvtLocMove ? eTrackMove : eTrackIdle, ap, pp, lp))
goto out;
pp= lp;
FeedbackOnce(tracker, ap, pp, TRUE); // new feedback
}
FeedbackOnce(tracker, ap, pp, FALSE); // clear last feedback
tracker->TrackConstrain(ap, pp, &lp);
if (! tracker->TestFlag(eCmdMoveEvents)) {
bwin->Grab(FALSE, fullscreen);
havereset= TRUE;
level--;
}
TrackOnce(&tracker, IsOpen() ? eTrackRelease : eTrackExit, ap, pp, lp);
if (tracker->TestFlag(eCmdMoveEvents)) {
haveSeenUp= FALSE;
goto restart;
}
out:
Focus();
if (! havereset) {
bwin->Grab(FALSE, fullscreen);
level--;
}
return tracker;
}
OStream& Clipper::PrintOn(OStream &s)
{
VObject::PrintOn(s);
return s << minExtent SP << scale SP << vop SP << bgcolor SP;
}
IStream& Clipper::ReadFrom(IStream &s)
{
VObject::ReadFrom(s);
s >> minExtent >> scale >> vop >> bgcolor;
Add(vop);
SetContentRect(contentRect, TRUE);
return s;
}
void Clipper::InspectorId(char *buf, int sz)
{
if (vop)
vop->InspectorId(buf, sz);
else
VObject::InspectorId(buf, sz);
}
void Clipper::CollectParts(Collection* col)
{
VObject::CollectParts(col);
if (vop)
col->Add(vop);
}